package com.itheima.getwayservice.filters;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.servlet.http.HttpServletRequest;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;

@Component
@Slf4j
public class AdminAuthorizeFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        log.info("请求来了=== >" + request.getPath().toString());
        String token = request.getHeaders().getFirst("token");
        if (token == null) {
            return setUnauthorizedResponse(exchange, "非法登录");
        }

        //http://localhost:8010/user/es/getIndex  path的结果是端口后面的东西
        String path = request.getPath().toString();
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        if (antPathMatcher.match("user/**", path) ||
                antPathMatcher.match("order/**", path)
        ) {
            //匹配成功就放行
            return chain.filter(exchange);
        }


        //String ip = getIPAdress(request,response);
//        System.out.println(ip);
        return chain.filter(exchange);
    }

    /**
     * 获取ip
     *
     * @param request
     * @return
     */
    private String getIPAdress(ServerHttpRequest request, ServerHttpResponse response) {
        String ip = null;

        //客户端通过代理服务器发送请求时，代理服务器会将客户端的IP地址添加到 X-Forwarded-For 头字段中，并将自己的IP地址作为新的请求源I
        //假设有一个请求链路如下：客户端 -> 代理服务器 A -> 负载均衡器 B -> 后端服务器 C。其中，客户端的原始IP地址是 192.168.0.1。
        //在这种情况下，HTTP请求的 X-Forwarded-For 头字段可能是这样的：X-Forwarded-For: 192.168.0.1, proxyA, loadBalancerB
        String ipAddresses = request.getHeaders().getFirst("X-Forwarded-For");
        //在postman里面测试的时候 -- 测试结论,X-Forwarded-For  使用getFirst方法获取第一个的值  使用get方法能获取多个值
        List<String> list = request.getHeaders().get("X-Forwarded-For");

        //request.getHeaders().getFirst("X-Forwarded-For");  请求头字段的第一个值
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //表示客户端连接请求经过的最后一个代理服务器的IP地址。它通常由最后一个代理服务器添加到HTTP请求中，以提供有关客户端连接的一些信息
            ipAddresses = request.getHeaders().getFirst("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // WL-Proxy-Client-IP：weblogic 服务代理 -- 是Oracle提供的一种Java应用服务
            //表示经过WebLogic服务器上Web服务器插件的客户端的真实IP地址
            ipAddresses = request.getHeaders().getFirst("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // HTTP_CLIENT_IP：有些代理服务器
            //在一些特定的网络环境中，代理服务器或网络设备可能会将客户端的真实IP地址添加到HTTP请求头中的 HTTP_CLIENT_IP 字段中
            ipAddresses = request.getHeaders().getFirst("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // X-Real-IP：nginx服务代理
            //代理服务器或负载均衡器可能会将客户端的真实IP地址添加到HTTP请求头中的 X-Real-IP 字段中
            ipAddresses = request.getHeaders().getFirst("X-Real-IP");
        }

        // 有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        // 还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            System.out.println(request.getRemoteAddress().getAddress().getAddress());
//            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }

    @Override
    public int getOrder() {
        return -1;
    }

    /**
     * @author: shenghuan
     * @Date: 2021/5/13 15:54
     * @Description:安全校验异常处理
     */
    private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg) {
        //todo::这里传入的参数以后可能会需要增加一个date,此时在里写死之后就会显得不够灵活
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", 401);
        map.put("msg", msg);

        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);

        log.error("[安全校验异常处理]请求路径:{}", exchange.getRequest().getPath());
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            return bufferFactory.wrap(JSON.toJSONBytes(map));
        }));
    }
}
